/*
* (c) 2014 University of Applied Sciences, Karlsruhe
* Project "Segmentation of depth data of a plenoptic camera"
* summer semester 2014
*
* segmentation_3d.h
* This file contains the executing layer of the segmentation program. In here, the segmentation method is selected and function calls are forwarded
* to the algorithms.
*/

#ifndef _SEGMENTATION_3D_H_
#define _SEGMENTATION_3D_H_

#include <ostream>
#include <vector>

#include <Eigen/Dense>
#include <opencv2/opencv.hpp>
#include <pcl/common/distances.h>

#include "sgBase/camera_3d.h"
#include "sgBase/geometrics/line_3d.h"

#include "sgMain/2d/contour_2d.h"
#include "sgMain/3d/contour_3d.h"

#include "sgExecution/find_contours_2d.h"
#include "sgExecution/contour_fitting_3d.h"

using namespace sgBase;
using namespace sgMain;

namespace sgExecution
{
	/**
	The segmentation approach to use. Classical approach means that the segmentation is directly done on the point cloud,
	the contour fitting approach uses a two-step algorithm (first perform edge detection on the color image and then fit 
	the contours into the 3D point cloud).
	*/
	enum Segmentation3DApproach
	{
		APPROACH_CLASSICAL,
		APPROACH_CONTOUR_FITTING
	};

	/**
	Class to handle the segmentation process. It is responsible for user querying, algorithm execution and result data handling.
	*/
	class Segmentation3D
	{
	private:
		Camera3D plenopticCamera; /// The camera object.
		cv::Mat matrixOfIntrinsicParameters; /// The intrinsic parameters.
		cv::Mat colorImage; /// The color image.
		cv::Mat depthImage; /// The depth map, as given by the Raytrix camera software.
		pcl::PointCloud<pcl::PointXYZRGB>::Ptr depthCloud; /// The depth values transformed into a point cloud (in camera space).

		/**
		Helper function to fit contous into 3D point data and to store the results in a text file. This function is currently only implemented for debug
		purpose and can be removed in future releases.
		\param[in] contourFitting The contour fitting class which stores the image 2D contours.
		\param[in] depthFittingMethod The method to fit the contours into the depth data.
		\param[in] radius The maximum distance of a depth data point from a 2D contour (if projected on the image plane).
		\param[in] saveToFile Flag to define whether the results should be stored in a file.
		\param[in] filename The file into which the results should be stored.
		\return The fitted contours in 3D space.
		*/
		std::vector<Contour3D> ExecuteDepthFitting(ContourFitting3D contourFitting, Segmentation3DDepthFittingMethod depthFittingMethod, double radius, bool saveToFile, std::string filename);

	public:
		cv::Mat contourImage; /// the binary edge image.
		std::vector<Contour2D> contours2D; /// list of the found contours (2D)
		std::vector<Contour3D> contours3D; /// list of the contours fitted into 3D space (in world coordinates)
		bool showResults; /// flag wether the results should be displayed for the user.

		/**
		Constructor.
		\param[in] cameraParameterFileName File name of the XML file containing the camera intrinsic parameters.
		\param[in] colorImageFileName File name of the color image.
		\param[in] depthImageFileName File name of the depth map image.
		*/
		Segmentation3D(std::string cameraParameterFileName, std::string colorImageFileName, std::string depthImageFileName);

		/**
		Function which starts the segmentation process.
		*/
		int Execute();

		/**
		Performs a contour fitting 3D segmentation.
		\param[in] lineDetectionMethod The algorithm which is used to perform the contour detection on the color image.
		\param[in] depthFittingMethod The algorithm used to fit the 2D contours in the 3D point cloud.
		\return -1 if the contour detection failed, otherwise 0.
		*/
		int ExecuteContourFittingApproach(Segmentation3DContourDetectionMethod lineDetectionMethod, Segmentation3DDepthFittingMethod depthFittingMethod);
		
		/**
		Performs a classical segmentation (RANSAC 3D) on the point cloud.
		*/ 
		int ExecuteClassicalApproach();
	};

	namespace Segmentation3DHelper
	{
		const std::string DefaultOutputPath = "output.txt"; /// Default filename if results should be stored in a file but no input file name is given

		/**
		Queries the segmentation approach (classical = RANSAC3D or two-step approach by using contour detection and depth fitting) from the user.
		*/
		Segmentation3DApproach QuerySegmentationApproach();

		/**
		Queries the algorithm which should be used to perform the edge detection on the image.
		*/
		Segmentation3DContourDetectionMethod QueryContourDetectionMethod();

		/**
		Queries the algorithm which should be used to fit the contours into 3D space.
		*/
		Segmentation3DDepthFittingMethod QueryLineFittingMethod();

		/**
		Helper function to query a boolean from the user.
		*/
		bool QueryBool();

		/**
		Helper function to query if the results should be stored.
		\param[out] fileStream The filestream to the file in which the results should be stored, if desired by the user.
		\return true if the results should be stored, then it is guaranteed that fileStream is set, otherwise false.
		*/
		bool QueryStoreInFile(std::ofstream &fileStream);
	}
}

#endif